home

Load Libraries


### https://cran.r-project.org/web/packages/udpipe/vignettes/udpipe-usecase-postagging-lemmatisation.html
library(udpipe)
ud_model <- udpipe_download_model(language = "english")
library(tidyverse)
library(tidyr)
library(dplyr)
library(ggplot2)
library(ggrepel)
library(knitr)
library(tm)
library(quanteda)
library(lattice)
library(latticeExtra)
library(plotly)
library(pdp)
library(patchwork)

Load the FW functions


### CODE DIRECTLY FROM: https://burtmonroe.github.io/TextAsDataCourse/Tutorials/TADA-FightinWords.nb.html#
fwgroups <- function(dtm, groups, pair = NULL, weights = rep(1,nrow(dtm)), k.prior = .1) {
  
  weights[is.na(weights)] <- 0
  
  weights <- weights/mean(weights)
  
  zero.doc <- rowSums(dtm)==0 | weights==0
  zero.term <- colSums(dtm[!zero.doc,])==0
  
  dtm.nz <- apply(dtm[!zero.doc,!zero.term],2,"*", weights[!zero.doc])
  
  g.prior <- tcrossprod(rowSums(dtm.nz),colSums(dtm.nz))/sum(dtm.nz)
  
  # 
  
  g.posterior <- as.matrix(dtm.nz + k.prior*g.prior)
  
  groups <- groups[!zero.doc]
  groups <- droplevels(groups)
  
  g.adtm <- as.matrix(aggregate(x=g.posterior,by=list(groups=groups),FUN=sum)[,-1])
  rownames(g.adtm) <- levels(groups)
  
  g.ladtm <- log(g.adtm)
  
  g.delta <- t(scale( t(scale(g.ladtm, center=T, scale=F)), center=T, scale=F))
  
  g.adtm_w <- -sweep(g.adtm,1,rowSums(g.adtm)) # terms not w spoken by k
  g.adtm_k <- -sweep(g.adtm,2,colSums(g.adtm)) # w spoken by groups other than k
  g.adtm_kw <- sum(g.adtm) - g.adtm_w - g.adtm_k - g.adtm # total terms not w or k 
  
  g.se <- sqrt(1/g.adtm + 1/g.adtm_w + 1/g.adtm_k + 1/g.adtm_kw)
  
  g.zeta <- g.delta/g.se
  
  g.counts <- as.matrix(aggregate(x=dtm.nz, by = list(groups=groups), FUN=sum)[,-1])
  
  if (!is.null(pair)) {
    pr.delta <- t(scale( t(scale(g.ladtm[pair,], center = T, scale =F)), center=T, scale=F))
    pr.adtm_w <- -sweep(g.adtm[pair,],1,rowSums(g.adtm[pair,]))
    pr.adtm_k <- -sweep(g.adtm[pair,],2,colSums(g.adtm[pair,])) # w spoken by groups other than k
    pr.adtm_kw <- sum(g.adtm[pair,]) - pr.adtm_w - pr.adtm_k - g.adtm[pair,] # total terms not w or k
    pr.se <- sqrt(1/g.adtm[pair,] + 1/pr.adtm_w + 1/pr.adtm_k + 1/pr.adtm_kw)
    pr.zeta <- pr.delta/pr.se
    
    return(list(zeta=pr.zeta[1,], delta=pr.delta[1,],se=pr.se[1,], counts = colSums(dtm.nz), acounts = colSums(g.adtm)))
  } else {
    return(list(zeta=g.zeta,delta=g.delta,se=g.se,counts=g.counts,acounts=g.adtm))
  }
}

############## FIGHTIN' WORDS PLOTTING FUNCTION

# helper function
makeTransparent<-function(someColor, alpha=100)
{
  newColor<-col2rgb(someColor)
  apply(newColor, 2, function(curcoldata){rgb(red=curcoldata[1], green=curcoldata[2],
                                              blue=curcoldata[3],alpha=alpha, maxColorValue=255)})
}

fw.ggplot.groups <- function(fw.ch, groups.use = as.factor(rownames(fw.ch$zeta)), max.words = 50, max.countrank = 400, colorpalette=rep("black",length(groups.use)), sizescale=2, title="Comparison of Terms by Groups", subtitle = "", caption = "Group-specific terms are ordered by Fightin' Words statistic (Monroe, et al. 2008)") {
  if (is.null(dim(fw.ch$zeta))) {## two-group fw object consists of vectors, not matrices
    zetarankmat <- cbind(rank(-fw.ch$zeta),rank(fw.ch$zeta))
    colnames(zetarankmat) <- groups.use
    countrank <- rank(-(fw.ch$counts))
  } else {
    zetarankmat <- apply(-fw.ch$zeta[groups.use,],1,rank)
    countrank <- rank(-colSums(fw.ch$counts))
  }
  wideplotmat <- as_tibble(cbind(zetarankmat,countrank=countrank))
  wideplotmat$term=names(countrank)
  #rankplot <- gather(wideplotmat, party, zetarank, 1:ncol(zetarankmat))
  rankplot <- gather(wideplotmat, groups.use, zetarank, 1:ncol(zetarankmat))
  rankplot$plotsize <- sizescale*(50/(rankplot$zetarank))^(1/4)
  rankplot <- rankplot[rankplot$zetarank < max.words + 1 & rankplot$countrank<max.countrank+1,]
  rankplot$groups.use <- factor(rankplot$groups.use,levels=groups.use)
  
  p <- ggplot(rankplot, aes((nrow(rankplot)-countrank)^1, -(zetarank^1), colour=groups.use)) + 
    geom_point(show.legend=F,size=sizescale/2) + 
    theme_classic() +
    theme(axis.ticks=element_blank(), axis.text=element_blank() ) +
    ylim(-max.words,40) +
    facet_grid(groups.use ~ .) +
    geom_text_repel(aes(label = term), size = rankplot$plotsize, point.padding=.05,
                    box.padding = unit(0.20, "lines"), show.legend=F) +
    scale_colour_manual(values = alpha(colorpalette, .7)) + 
#    labs(x="Terms used more frequently overall →", y="Terms used more frequently by group →",  title=title, subtitle=subtitle , caption = caption) 
    labs(x=paste("Terms used more frequently overall -->"), y=paste("Terms used more frequently by group -->"),  title=title, subtitle=subtitle , caption = caption) 
  
}

fw.keys <- function(fw.ch,n.keys=10) {
  n.groups <- nrow(fw.ch$zeta)
  keys <- matrix("",n.keys,n.groups)
  colnames(keys) <- rownames(fw.ch$zeta)
  
  for (g in 1:n.groups) {
    keys[,g] <- names(sort(fw.ch$zeta[g,],dec=T)[1:n.keys])
  }
  keys
}

Compare NYT 1994-2010: Before and After “extremist”

Load and clean the data


text_cleaner<-function(corpus){
  tempcorpus<-Corpus(VectorSource(corpus))
  tempcorpus<-tm_map(tempcorpus,
                    removePunctuation)
  tempcorpus<-tm_map(tempcorpus,
                    stripWhitespace)
  tempcorpus<-tm_map(tempcorpus,
                    removeNumbers)
  tempcorpus<-tm_map(tempcorpus,
                     removeWords, stopwords("english"))
  tempcorpus<-tm_map(tempcorpus, 
                    stemDocument)
  return(tempcorpus)
}

Calculate FW.


##################################################################

fw.extrem <- fwgroups(extrem_dtm, groups=extrem_NYT.dfm.long$Context)

##################################################################

message(rm(extrem_dtm))
message(rm(e))

Get and show the top words per group by zeta.


fwkeys.extrem <- fw.keys(fw.extrem, n.keys=20)
cols <- rev(colnames(fwkeys.extrem))
fwkeys.extrem <- fwkeys.extrem[,cols]

##################################################################

kable(fwkeys.extrem)
Context.before Context.after
rightw group
mesopotamia view
homegrown element
sunni organ
islamic movement
paint hama
portray activ
jewish agenda
alqaida settler
yitzhak militia
evid caus
secur foreign
assassin respons
member by
minist foreignl
track oppos
iraq fring
belong posit
small led
monitor addit
NA

Plot: Comparing Words Before (in Blue), and After (in Red)


p.fw.extrem <- fw.ggplot.groups(fw.extrem,sizescale=4,max.words=200,
                                max.countrank=400,colorpalette=c("red","blue"),
                                 title = 'Comparison of Terms Before and After "Extremist"')
p.fw.extrem

Calculate Parts of speech by before and after


ud_model <- udpipe_load_model(ud_model$file_model)

txt <-as.character(extrem_NYT.dfm.long$context.text)

x_udp <- udpipe_annotate(ud_model, x = txt, doc_id = seq_along(txt))
x <- as.data.frame(x_udp)

x$doc_id <-as.integer(x$doc_id)

##################################################################

x_odd.before <- x[x$doc_id %% 2 == 1,]
x_even.after <-x[x$doc_id %% 2 == 0, ]

Bar Charts for Parts of Speech

Cooccurences

Cooccurences (part 2)


Corrs(x_odd.before)
Corrs(x_even.after)
NA

Extrem(ist) Fightin’ Words Over Time

home

LS0tCnRpdGxlOiAiRXh0cmVtKGlzdCkgRmlnaHRpbicgV29yZHMiCmF1dGhvcjogIkJyZWFubmEgRS4gR3JlZW4iCnN1YnRpdGxlOiAKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICB0aGVtZTogdW5pdGVkCiAgICB0b2M6IHllcwotLS0KCltob21lXShodHRwczovL2JyZWdyZWVuLmdpdGh1Yi5pby8pCgojIyBMb2FkIExpYnJhcmllcwoKYGBge3IgbG9hZCBsaWJyYXJpZXMsIHJlc3VsdHM9J2hpZGUnfQoKIyMjIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy91ZHBpcGUvdmlnbmV0dGVzL3VkcGlwZS11c2VjYXNlLXBvc3RhZ2dpbmctbGVtbWF0aXNhdGlvbi5odG1sCmxpYnJhcnkodWRwaXBlKQp1ZF9tb2RlbCA8LSB1ZHBpcGVfZG93bmxvYWRfbW9kZWwobGFuZ3VhZ2UgPSAiZW5nbGlzaCIpCgpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodG0pCmxpYnJhcnkocXVhbnRlZGEpCmxpYnJhcnkobGF0dGljZSkKbGlicmFyeShsYXR0aWNlRXh0cmEpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KHBkcCkKbGlicmFyeShwYXRjaHdvcmspCgpgYGAKCiMjIExvYWQgdGhlIEZXIGZ1bmN0aW9ucwoKYGBge3IgbG9hZF9md19mdW5jdGlvbnN9CgojIyMgQ09ERSBESVJFQ1RMWSBGUk9NOiBodHRwczovL2J1cnRtb25yb2UuZ2l0aHViLmlvL1RleHRBc0RhdGFDb3Vyc2UvVHV0b3JpYWxzL1RBREEtRmlnaHRpbldvcmRzLm5iLmh0bWwjCmZ3Z3JvdXBzIDwtIGZ1bmN0aW9uKGR0bSwgZ3JvdXBzLCBwYWlyID0gTlVMTCwgd2VpZ2h0cyA9IHJlcCgxLG5yb3coZHRtKSksIGsucHJpb3IgPSAuMSkgewogIAogIHdlaWdodHNbaXMubmEod2VpZ2h0cyldIDwtIDAKICAKICB3ZWlnaHRzIDwtIHdlaWdodHMvbWVhbih3ZWlnaHRzKQogIAogIHplcm8uZG9jIDwtIHJvd1N1bXMoZHRtKT09MCB8IHdlaWdodHM9PTAKICB6ZXJvLnRlcm0gPC0gY29sU3VtcyhkdG1bIXplcm8uZG9jLF0pPT0wCiAgCiAgZHRtLm56IDwtIGFwcGx5KGR0bVshemVyby5kb2MsIXplcm8udGVybV0sMiwiKiIsIHdlaWdodHNbIXplcm8uZG9jXSkKICAKICBnLnByaW9yIDwtIHRjcm9zc3Byb2Qocm93U3VtcyhkdG0ubnopLGNvbFN1bXMoZHRtLm56KSkvc3VtKGR0bS5ueikKICAKICAjIAogIAogIGcucG9zdGVyaW9yIDwtIGFzLm1hdHJpeChkdG0ubnogKyBrLnByaW9yKmcucHJpb3IpCiAgCiAgZ3JvdXBzIDwtIGdyb3Vwc1shemVyby5kb2NdCiAgZ3JvdXBzIDwtIGRyb3BsZXZlbHMoZ3JvdXBzKQogIAogIGcuYWR0bSA8LSBhcy5tYXRyaXgoYWdncmVnYXRlKHg9Zy5wb3N0ZXJpb3IsYnk9bGlzdChncm91cHM9Z3JvdXBzKSxGVU49c3VtKVssLTFdKQogIHJvd25hbWVzKGcuYWR0bSkgPC0gbGV2ZWxzKGdyb3VwcykKICAKICBnLmxhZHRtIDwtIGxvZyhnLmFkdG0pCiAgCiAgZy5kZWx0YSA8LSB0KHNjYWxlKCB0KHNjYWxlKGcubGFkdG0sIGNlbnRlcj1ULCBzY2FsZT1GKSksIGNlbnRlcj1ULCBzY2FsZT1GKSkKICAKICBnLmFkdG1fdyA8LSAtc3dlZXAoZy5hZHRtLDEscm93U3VtcyhnLmFkdG0pKSAjIHRlcm1zIG5vdCB3IHNwb2tlbiBieSBrCiAgZy5hZHRtX2sgPC0gLXN3ZWVwKGcuYWR0bSwyLGNvbFN1bXMoZy5hZHRtKSkgIyB3IHNwb2tlbiBieSBncm91cHMgb3RoZXIgdGhhbiBrCiAgZy5hZHRtX2t3IDwtIHN1bShnLmFkdG0pIC0gZy5hZHRtX3cgLSBnLmFkdG1fayAtIGcuYWR0bSAjIHRvdGFsIHRlcm1zIG5vdCB3IG9yIGsgCiAgCiAgZy5zZSA8LSBzcXJ0KDEvZy5hZHRtICsgMS9nLmFkdG1fdyArIDEvZy5hZHRtX2sgKyAxL2cuYWR0bV9rdykKICAKICBnLnpldGEgPC0gZy5kZWx0YS9nLnNlCiAgCiAgZy5jb3VudHMgPC0gYXMubWF0cml4KGFnZ3JlZ2F0ZSh4PWR0bS5ueiwgYnkgPSBsaXN0KGdyb3Vwcz1ncm91cHMpLCBGVU49c3VtKVssLTFdKQogIAogIGlmICghaXMubnVsbChwYWlyKSkgewogICAgcHIuZGVsdGEgPC0gdChzY2FsZSggdChzY2FsZShnLmxhZHRtW3BhaXIsXSwgY2VudGVyID0gVCwgc2NhbGUgPUYpKSwgY2VudGVyPVQsIHNjYWxlPUYpKQogICAgcHIuYWR0bV93IDwtIC1zd2VlcChnLmFkdG1bcGFpcixdLDEscm93U3VtcyhnLmFkdG1bcGFpcixdKSkKICAgIHByLmFkdG1fayA8LSAtc3dlZXAoZy5hZHRtW3BhaXIsXSwyLGNvbFN1bXMoZy5hZHRtW3BhaXIsXSkpICMgdyBzcG9rZW4gYnkgZ3JvdXBzIG90aGVyIHRoYW4gawogICAgcHIuYWR0bV9rdyA8LSBzdW0oZy5hZHRtW3BhaXIsXSkgLSBwci5hZHRtX3cgLSBwci5hZHRtX2sgLSBnLmFkdG1bcGFpcixdICMgdG90YWwgdGVybXMgbm90IHcgb3IgawogICAgcHIuc2UgPC0gc3FydCgxL2cuYWR0bVtwYWlyLF0gKyAxL3ByLmFkdG1fdyArIDEvcHIuYWR0bV9rICsgMS9wci5hZHRtX2t3KQogICAgcHIuemV0YSA8LSBwci5kZWx0YS9wci5zZQogICAgCiAgICByZXR1cm4obGlzdCh6ZXRhPXByLnpldGFbMSxdLCBkZWx0YT1wci5kZWx0YVsxLF0sc2U9cHIuc2VbMSxdLCBjb3VudHMgPSBjb2xTdW1zKGR0bS5ueiksIGFjb3VudHMgPSBjb2xTdW1zKGcuYWR0bSkpKQogIH0gZWxzZSB7CiAgICByZXR1cm4obGlzdCh6ZXRhPWcuemV0YSxkZWx0YT1nLmRlbHRhLHNlPWcuc2UsY291bnRzPWcuY291bnRzLGFjb3VudHM9Zy5hZHRtKSkKICB9Cn0KCiMjIyMjIyMjIyMjIyMjIEZJR0hUSU4nIFdPUkRTIFBMT1RUSU5HIEZVTkNUSU9OCgojIGhlbHBlciBmdW5jdGlvbgptYWtlVHJhbnNwYXJlbnQ8LWZ1bmN0aW9uKHNvbWVDb2xvciwgYWxwaGE9MTAwKQp7CiAgbmV3Q29sb3I8LWNvbDJyZ2Ioc29tZUNvbG9yKQogIGFwcGx5KG5ld0NvbG9yLCAyLCBmdW5jdGlvbihjdXJjb2xkYXRhKXtyZ2IocmVkPWN1cmNvbGRhdGFbMV0sIGdyZWVuPWN1cmNvbGRhdGFbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBibHVlPWN1cmNvbGRhdGFbM10sYWxwaGE9YWxwaGEsIG1heENvbG9yVmFsdWU9MjU1KX0pCn0KCmZ3LmdncGxvdC5ncm91cHMgPC0gZnVuY3Rpb24oZncuY2gsIGdyb3Vwcy51c2UgPSBhcy5mYWN0b3Iocm93bmFtZXMoZncuY2gkemV0YSkpLCBtYXgud29yZHMgPSA1MCwgbWF4LmNvdW50cmFuayA9IDQwMCwgY29sb3JwYWxldHRlPXJlcCgiYmxhY2siLGxlbmd0aChncm91cHMudXNlKSksIHNpemVzY2FsZT0yLCB0aXRsZT0iQ29tcGFyaXNvbiBvZiBUZXJtcyBieSBHcm91cHMiLCBzdWJ0aXRsZSA9ICIiLCBjYXB0aW9uID0gIkdyb3VwLXNwZWNpZmljIHRlcm1zIGFyZSBvcmRlcmVkIGJ5IEZpZ2h0aW4nIFdvcmRzIHN0YXRpc3RpYyAoTW9ucm9lLCBldCBhbC4gMjAwOCkiKSB7CiAgaWYgKGlzLm51bGwoZGltKGZ3LmNoJHpldGEpKSkgeyMjIHR3by1ncm91cCBmdyBvYmplY3QgY29uc2lzdHMgb2YgdmVjdG9ycywgbm90IG1hdHJpY2VzCiAgICB6ZXRhcmFua21hdCA8LSBjYmluZChyYW5rKC1mdy5jaCR6ZXRhKSxyYW5rKGZ3LmNoJHpldGEpKQogICAgY29sbmFtZXMoemV0YXJhbmttYXQpIDwtIGdyb3Vwcy51c2UKICAgIGNvdW50cmFuayA8LSByYW5rKC0oZncuY2gkY291bnRzKSkKICB9IGVsc2UgewogICAgemV0YXJhbmttYXQgPC0gYXBwbHkoLWZ3LmNoJHpldGFbZ3JvdXBzLnVzZSxdLDEscmFuaykKICAgIGNvdW50cmFuayA8LSByYW5rKC1jb2xTdW1zKGZ3LmNoJGNvdW50cykpCiAgfQogIHdpZGVwbG90bWF0IDwtIGFzX3RpYmJsZShjYmluZCh6ZXRhcmFua21hdCxjb3VudHJhbms9Y291bnRyYW5rKSkKICB3aWRlcGxvdG1hdCR0ZXJtPW5hbWVzKGNvdW50cmFuaykKICAjcmFua3Bsb3QgPC0gZ2F0aGVyKHdpZGVwbG90bWF0LCBwYXJ0eSwgemV0YXJhbmssIDE6bmNvbCh6ZXRhcmFua21hdCkpCiAgcmFua3Bsb3QgPC0gZ2F0aGVyKHdpZGVwbG90bWF0LCBncm91cHMudXNlLCB6ZXRhcmFuaywgMTpuY29sKHpldGFyYW5rbWF0KSkKICByYW5rcGxvdCRwbG90c2l6ZSA8LSBzaXplc2NhbGUqKDUwLyhyYW5rcGxvdCR6ZXRhcmFuaykpXigxLzQpCiAgcmFua3Bsb3QgPC0gcmFua3Bsb3RbcmFua3Bsb3QkemV0YXJhbmsgPCBtYXgud29yZHMgKyAxICYgcmFua3Bsb3QkY291bnRyYW5rPG1heC5jb3VudHJhbmsrMSxdCiAgcmFua3Bsb3QkZ3JvdXBzLnVzZSA8LSBmYWN0b3IocmFua3Bsb3QkZ3JvdXBzLnVzZSxsZXZlbHM9Z3JvdXBzLnVzZSkKICAKICBwIDwtIGdncGxvdChyYW5rcGxvdCwgYWVzKChucm93KHJhbmtwbG90KS1jb3VudHJhbmspXjEsIC0oemV0YXJhbmteMSksIGNvbG91cj1ncm91cHMudXNlKSkgKyAKICAgIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQ9RixzaXplPXNpemVzY2FsZS8yKSArIAogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIHRoZW1lKGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQ9ZWxlbWVudF9ibGFuaygpICkgKwogICAgeWxpbSgtbWF4LndvcmRzLDQwKSArCiAgICBmYWNldF9ncmlkKGdyb3Vwcy51c2UgfiAuKSArCiAgICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gdGVybSksIHNpemUgPSByYW5rcGxvdCRwbG90c2l6ZSwgcG9pbnQucGFkZGluZz0uMDUsCiAgICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSB1bml0KDAuMjAsICJsaW5lcyIpLCBzaG93LmxlZ2VuZD1GKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGFscGhhKGNvbG9ycGFsZXR0ZSwgLjcpKSArIAojICAgIGxhYnMoeD0iVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgb3ZlcmFsbCDihpIiLCB5PSJUZXJtcyB1c2VkIG1vcmUgZnJlcXVlbnRseSBieSBncm91cCDihpIiLCAgdGl0bGU9dGl0bGUsIHN1YnRpdGxlPXN1YnRpdGxlICwgY2FwdGlvbiA9IGNhcHRpb24pIAogICAgbGFicyh4PXBhc3RlKCJUZXJtcyB1c2VkIG1vcmUgZnJlcXVlbnRseSBvdmVyYWxsIC0tPiIpLCB5PXBhc3RlKCJUZXJtcyB1c2VkIG1vcmUgZnJlcXVlbnRseSBieSBncm91cCAtLT4iKSwgIHRpdGxlPXRpdGxlLCBzdWJ0aXRsZT1zdWJ0aXRsZSAsIGNhcHRpb24gPSBjYXB0aW9uKSAKICAKfQoKZncua2V5cyA8LSBmdW5jdGlvbihmdy5jaCxuLmtleXM9MTApIHsKICBuLmdyb3VwcyA8LSBucm93KGZ3LmNoJHpldGEpCiAga2V5cyA8LSBtYXRyaXgoIiIsbi5rZXlzLG4uZ3JvdXBzKQogIGNvbG5hbWVzKGtleXMpIDwtIHJvd25hbWVzKGZ3LmNoJHpldGEpCiAgCiAgZm9yIChnIGluIDE6bi5ncm91cHMpIHsKICAgIGtleXNbLGddIDwtIG5hbWVzKHNvcnQoZncuY2gkemV0YVtnLF0sZGVjPVQpWzE6bi5rZXlzXSkKICB9CiAga2V5cwp9CmBgYAoKCiMjIENvbXBhcmUgTllUIDE5OTQtMjAxMDogQmVmb3JlIGFuZCBBZnRlciAiZXh0cmVtaXN0IgoKKkxvYWQgYW5kIGNsZWFuIHRoZSBkYXRhKgoKICAqIHRvIHN0cmluZyAmIGxvd2VyIHRleHQKICAqIHBpdm90IHRvIGxvbmcgZm9ybWF0CiAgKiBhcHBseSB0ZXh0X2NsZWFuZXIgdG8gb25lIGNvbHVtbiAiY29udGV4dC50ZXh0IgoKYGBge3J9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyMjIFRleHQgQ2xlYW5pbmcgRnVuY3Rpb24KCnRleHRfY2xlYW5lcjwtZnVuY3Rpb24oY29ycHVzKXsKICB0ZW1wY29ycHVzPC1Db3JwdXMoVmVjdG9yU291cmNlKGNvcnB1cykpCiAgdGVtcGNvcnB1czwtdG1fbWFwKHRlbXBjb3JwdXMsCiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlUHVuY3R1YXRpb24pCiAgdGVtcGNvcnB1czwtdG1fbWFwKHRlbXBjb3JwdXMsCiAgICAgICAgICAgICAgICAgICAgc3RyaXBXaGl0ZXNwYWNlKQogIHRlbXBjb3JwdXM8LXRtX21hcCh0ZW1wY29ycHVzLAogICAgICAgICAgICAgICAgICAgIHJlbW92ZU51bWJlcnMpCiAgdGVtcGNvcnB1czwtdG1fbWFwKHRlbXBjb3JwdXMsCiAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuZ2xpc2giKSkKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywgCiAgICAgICAgICAgICAgICAgICAgc3RlbURvY3VtZW50KQogIHJldHVybih0ZW1wY29ycHVzKQp9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKYGBgCgpgYGB7ciBjbGVhbl90ZXh0LCBlY2hvPUZBTFNFLCByZXN1bHRzPSBGQUxTRX0KCmV4dHJlbV9OWVQuZGZtIDwtIHJlYWQuZGVsaW0oImV4dHJlbWlzdF85NDEwX05ZVC50eHQiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQpleHRyZW1fTllULmRmbSRwdWJkYXRlID0gc3Vic3RyKGV4dHJlbV9OWVQuZGZtJFRleHQuSUQsOSwxNikKZXh0cmVtX05ZVC5kZm0kcHViZGF0ZSA8LSBhcy5QT1NJWGN0KGV4dHJlbV9OWVQuZGZtJHB1YmRhdGUsIGZvcm1hdCA9ICIlWSVtJWQiKQoKCiMgZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5iZWZvcmUgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5iZWZvcmUsIHRvU3RyaW5nKQojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlID0gbGFwcGx5KGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlLCB0b2xvd2VyKQojIAojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYWZ0ZXIgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciwgdG9TdHJpbmcpCiMgZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciA9IGxhcHBseShleHRyZW1fTllULmRmbSRDb250ZXh0LmFmdGVyLCB0b2xvd2VyKQoKZXh0cmVtX05ZVC5kZm0gPC0gZXh0cmVtX05ZVC5kZm0gJT4lIGRpc3RpbmN0KENvbnRleHQuYmVmb3JlLCAua2VlcF9hbGwgPSBUUlVFKQoKZXh0cmVtX05ZVC5kZm0ubG9uZyA8LSBwaXZvdF9sb25nZXIoZXh0cmVtX05ZVC5kZm0sIGNvbHM9YyhDb250ZXh0LmJlZm9yZSwgQ29udGV4dC5hZnRlciksIG5hbWVzX3RvID0gIkNvbnRleHQiLCB2YWx1ZXNfdG8gPSAiY29udGV4dC50ZXh0IikKCmV4dHJlbV9OWVQuZGZtLmxvbmckQ29udGV4dCA8LSBhcy5mYWN0b3IoZXh0cmVtX05ZVC5kZm0ubG9uZyRDb250ZXh0KQoKZXh0cmVtZWNvcnB1cyA8LXRleHRfY2xlYW5lcihleHRyZW1fTllULmRmbS5sb25nJGNvbnRleHQudGV4dCkKCmBgYAoKCkNhbGN1bGF0ZSBGVy4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQoKZSA8LSBkZm0oZXh0cmVtZWNvcnB1cyRjb250ZW50KQptZXNzYWdlKGRpbShlKSkKCmV4dHJlbV9kdG0gPC0gY29udmVydChlLCB0bz0nZGF0YS5mcmFtZScpCmV4dHJlbV9kdG0gPC0gZXh0cmVtX2R0bVstYygxKV0KdyA8LSB3aGljaCggc2FwcGx5KGV4dHJlbV9kdG0sIGNsYXNzICkgPT0gJ2NoYXJhY3RlcicgKQoKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpmdy5leHRyZW0gPC0gZndncm91cHMoZXh0cmVtX2R0bSwgZ3JvdXBzPWV4dHJlbV9OWVQuZGZtLmxvbmckQ29udGV4dCkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKbWVzc2FnZShybShleHRyZW1fZHRtKSkKbWVzc2FnZShybShlKSkKCmBgYAoKCkdldCBhbmQgc2hvdyB0aGUgdG9wIHdvcmRzIHBlciBncm91cCBieSB6ZXRhLgoKYGBge3IgZWNobz1UUlVFfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmZ3a2V5cy5leHRyZW0gPC0gZncua2V5cyhmdy5leHRyZW0sIG4ua2V5cz0yMCkKY29scyA8LSByZXYoY29sbmFtZXMoZndrZXlzLmV4dHJlbSkpCmZ3a2V5cy5leHRyZW0gPC0gZndrZXlzLmV4dHJlbVssY29sc10KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKa2FibGUoZndrZXlzLmV4dHJlbSkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKYGBgCgoqUGxvdDogQ29tcGFyaW5nIFdvcmRzIEJlZm9yZSAoaW4gQmx1ZSksIGFuZCBBZnRlciAoaW4gUmVkKSoKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD00fQpwLmZ3LmV4dHJlbSA8LSBmdy5nZ3Bsb3QuZ3JvdXBzKGZ3LmV4dHJlbSxzaXplc2NhbGU9NCxtYXgud29yZHM9MjAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heC5jb3VudHJhbms9NDAwLGNvbG9ycGFsZXR0ZT1jKCJyZWQiLCJibHVlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gJ0NvbXBhcmlzb24gb2YgVGVybXMgQmVmb3JlIGFuZCBBZnRlciAiRXh0cmVtaXN0IicpCnAuZncuZXh0cmVtCgpgYGAKCiMjIENhbGN1bGF0ZSBQYXJ0cyBvZiBzcGVlY2ggYnkgYmVmb3JlIGFuZCBhZnRlcgoKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnVkX21vZGVsIDwtIHVkcGlwZV9sb2FkX21vZGVsKHVkX21vZGVsJGZpbGVfbW9kZWwpCgp0eHQgPC1hcy5jaGFyYWN0ZXIoZXh0cmVtX05ZVC5kZm0ubG9uZyRjb250ZXh0LnRleHQpCgp4X3VkcCA8LSB1ZHBpcGVfYW5ub3RhdGUodWRfbW9kZWwsIHggPSB0eHQsIGRvY19pZCA9IHNlcV9hbG9uZyh0eHQpKQp4IDwtIGFzLmRhdGEuZnJhbWUoeF91ZHApCgp4JGRvY19pZCA8LWFzLmludGVnZXIoeCRkb2NfaWQpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCgpgYGAKCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgp4X29kZC5iZWZvcmUgPC0geFt4JGRvY19pZCAlJSAyID09IDEsXQp4X2V2ZW4uYWZ0ZXIgPC14W3gkZG9jX2lkICUlIDIgPT0gMCwgXQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpgYGAKCmBgYHtyIGJhcmNoYXJ0ZnVuY3RzLCBlY2hvPUZBTFNFfQoKIyMgVU5JVkVSU0FMIFBvUwpVUE9TX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBzdGF0czEgPC0gdHh0X2ZyZXEoZGYxJHVwb3MpCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXkpKQogIAogIHN0YXRzMiA8LSB0eHRfZnJlcShkZjIkdXBvcykKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5LCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleSkpCiAgCiAgYyhiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gc3RhdHMxLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgbWFpbiA9ICJVUE9TIChVbml2ZXJzYWwgUGFydHMgb2YgU3BlZWNoKVxuIGZyZXF1ZW5jeSBvZiBvY2N1cnJlbmNlOiBCRUZPUkUgdnMgQUZURVIiLCAKICAgICAgICAgeGxhYiA9ICJGcmVxIiksIAogICAgYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IHN0YXRzMiwgY29sID0gICdza3libHVlJywKICAgICAgICAgeGxhYiA9ICJGcmVxIikpCgp9CgoKIyMgTk9VTlMKTk9VTlNfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIHN0YXRzMSA8LSBzdWJzZXQoZGYxLCB1cG9zICVpbiUgYygiTk9VTiIpKSAKICBzdGF0czEgPC0gdHh0X2ZyZXEoc3RhdHMxJHRva2VuKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXksIGxldmVscyA9IHJldihzdGF0czEka2V5KSkKICAKICBzdGF0czIgPC0gc3Vic2V0KGRmMiwgdXBvcyAlaW4lIGMoIk5PVU4iKSkgCiAgc3RhdHMyIDwtIHR4dF9mcmVxKHN0YXRzMiR0b2tlbikKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5LCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleSkpCiAgCiAgYyhiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gaGVhZChzdGF0czEsIDIwKSwgY29sID0gImNhZGV0Ymx1ZSIsIAogICAgICAgICAgIG1haW4gPSAiTW9zdCBvY2N1cnJpbmcgbm91bnM6IEJFRk9SRSB2cyBBRlRFUiIsIHhsYWIgPSAiRnJlcSIpLAogICAgICBiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gaGVhZChzdGF0czIsIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgICAgeGxhYiA9ICJGcmVxIikpCn0KCiMjIEFESkVDVElWRVMKQURKX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBzdGF0czEgPC0gc3Vic2V0KGRmMSwgdXBvcyAlaW4lIGMoIkFESiIpKSAKICBzdGF0czEgPC0gdHh0X2ZyZXEoc3RhdHMxJHRva2VuKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXksIGxldmVscyA9IHJldihzdGF0czEka2V5KSkKICAKICBzdGF0czIgPC0gc3Vic2V0KGRmMiwgdXBvcyAlaW4lIGMoIkFESiIpKSAKICBzdGF0czIgPC0gdHh0X2ZyZXEoc3RhdHMyJHRva2VuKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXksIGxldmVscyA9IHJldihzdGF0czIka2V5KSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJNb3N0IG9jY3VycmluZyBhZGplY3RpdmVzOiBCRUZPUkUgdnMgQUZURVIiLCB4bGFiID0gIkZyZXEiKSwKICAgICAgYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMyLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgIHhsYWIgPSAiRnJlcSIpKQp9CgojIyBVc2luZyBSQUtFIHRvIGZpbmQga2V5d29yZHMKUkFLRV9LV19iYXJjaGFydCA8LSBmdW5jdGlvbihkZjEsZGYyKXsKICAKICBzdGF0czEgPC0ga2V5d29yZHNfcmFrZSh4ID0gZGYxLCB0ZXJtID0gImxlbW1hIiwgZ3JvdXAgPSAiZG9jX2lkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICByZWxldmFudCA9IGRmMSR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSkKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXl3b3JkKSkKICAKICBzdGF0czIgPC0ga2V5d29yZHNfcmFrZSh4ID0gZGYyLCB0ZXJtID0gImxlbW1hIiwgZ3JvdXAgPSAiZG9jX2lkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICByZWxldmFudCA9IGRmMiR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSkKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXl3b3JkKSkKICAKICAKICBjKGJhcmNoYXJ0KGtleSB+IHJha2UsIGRhdGEgPSBoZWFkKHN1YnNldChzdGF0czEsIGZyZXEgPiAzKSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJLZXl3b3JkcyBpZGVudGlmaWVkIGJ5IFJBS0U6IEJFRk9SRSB2cyBBRlRFUiIsIAogICAgICAgICAgIHhsYWIgPSAiUmFrZSIpLAogICAgYmFyY2hhcnQoa2V5IH4gcmFrZSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMiwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgICAgeGxhYiA9ICJSYWtlIikpCn0KCiMjIFVzaW5nIFBvaW50d2lzZSBNdXR1YWwgSW5mb3JtYXRpb24gQ29sbG9jYXRpb25zClBXSV9iYXJjaGFydCA8LSBmdW5jdGlvbihkZjEsIGRmMil7CiAgCiAgZGYxJHdvcmQgPC0gdG9sb3dlcihkZjEkdG9rZW4pCiAgc3RhdHMxIDwtIGtleXdvcmRzX2NvbGxvY2F0aW9uKHggPSBkZjEsIHRlcm0gPSAid29yZCIsIGdyb3VwID0gImRvY19pZCIpCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleXdvcmQsIGxldmVscyA9IHJldihzdGF0czEka2V5d29yZCkpCiAgCiAgZGYyJHdvcmQgPC0gdG9sb3dlcihkZjIkdG9rZW4pCiAgc3RhdHMyIDwtIGtleXdvcmRzX2NvbGxvY2F0aW9uKHggPSBkZjIsIHRlcm0gPSAid29yZCIsIGdyb3VwID0gImRvY19pZCIpCiAgc3RhdHMyJGtleSA8LSBmYWN0b3Ioc3RhdHMyJGtleXdvcmQsIGxldmVscyA9IHJldihzdGF0czIka2V5d29yZCkpCiAgCiAgYyhiYXJjaGFydChrZXkgfiBwbWksIGRhdGEgPSBoZWFkKHN1YnNldChzdGF0czEsIGZyZXEgPiAzKSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJLZXl3b3JkcyBpZGVudGlmaWVkIGJ5IFBNSSBDb2xsb2NhdGlvbjogQkVGT1JFIHZzIEFGVEVSIiwgCiAgICAgICAgICAgeGxhYiA9ICJQTUkgKFBvaW50d2lzZSBNdXR1YWwgSW5mb3JtYXRpb24pIiksCiAgICAgIGJhcmNoYXJ0KGtleSB+IHBtaSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMiwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgICAgeGxhYiA9ICJQTUkgKFBvaW50d2lzZSBNdXR1YWwgSW5mb3JtYXRpb24pIikpCn0KCiMjIFVzaW5nIGEgc2VxdWVuY2Ugb2YgUE9TIHRhZ3MgKG5vdW4gcGhyYXNlcyAvIHZlcmIgcGhyYXNlcykKUE9TX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBkZjEkcGhyYXNlX3RhZyA8LSBhc19waHJhc2VtYWNoaW5lKGRmMSR1cG9zLCB0eXBlID0gInVwb3MiKQogIHN0YXRzMSA8LSBrZXl3b3Jkc19waHJhc2VzKHggPSBkZjEkcGhyYXNlX3RhZywgdGVybSA9IHRvbG93ZXIoZGYxJHRva2VuKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIihBfE4pKk4oUCtEKihBfE4pKk4pKiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNfcmVnZXggPSBUUlVFLCBkZXRhaWxlZCA9IEZBTFNFKQogIHN0YXRzMSA8LSBzdWJzZXQoc3RhdHMxLCBuZ3JhbSA+IDEgJiBmcmVxID4gMykKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXl3b3JkKSkKICAKICBkZjIkcGhyYXNlX3RhZyA8LSBhc19waHJhc2VtYWNoaW5lKGRmMiR1cG9zLCB0eXBlID0gInVwb3MiKQogIHN0YXRzMiA8LSBrZXl3b3Jkc19waHJhc2VzKHggPSBkZjIkcGhyYXNlX3RhZywgdGVybSA9IHRvbG93ZXIoZGYyJHRva2VuKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIihBfE4pKk4oUCtEKihBfE4pKk4pKiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNfcmVnZXggPSBUUlVFLCBkZXRhaWxlZCA9IEZBTFNFKQogIHN0YXRzMiA8LSBzdWJzZXQoc3RhdHMyLCBuZ3JhbSA+IDEgJiBmcmVxID4gMykKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXl3b3JkKSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJLZXl3b3JkcyAtIHNpbXBsZSBub3VuIHBocmFzZXM6IEJFRk9SRSB2cyBBRlRFUiIsIHhsYWIgPSAiRnJlcXVlbmN5IiksCiAgICAgIGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMiwgMjApLCBjb2wgPSAic2t5Ymx1ZSIsIAogICAgICAgICAgICAgICB4bGFiID0gIkZyZXF1ZW5jeSIpKQp9CmBgYAoKCiMjIEJhciBDaGFydHMgZm9yIFBhcnRzIG9mIFNwZWVjaCAKCmBgYHtyIFBPU2JhcmNoYXJ0cywgZWNobz1GQUxTRSwgZmlnLndpZHRoPTh9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKVVBPU19iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKTk9VTlNfYmFyY2hhcnQoeF9vZGQuYmVmb3JlLCB4X2V2ZW4uYWZ0ZXIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCkFESl9iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKUkFLRV9LV19iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKUFdJX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpQT1NfYmFyY2hhcnQoeF9vZGQuYmVmb3JlLCB4X2V2ZW4uYWZ0ZXIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKYGBgCgoKIyMgQ29vY2N1cmVuY2VzCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLndpZHRoPTZ9CgpDT19PQ19ub3VuX2Fkal9zYW1lX3NlbnQuYmVmb3JlIDwtIGZ1bmN0aW9uKGRmMSl7CiAgCiAgbGlicmFyeShpZ3JhcGgpCiAgbGlicmFyeShnZ3JhcGgpCiAgbGlicmFyeShnZ3Bsb3QyKQogIAogIGNvb2MgPC0gY29vY2N1cnJlbmNlKHggPSBzdWJzZXQoZGYxLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSksIAogICAgICAgICAgICAgICAgICAgICAgIHRlcm0gPSAibGVtbWEiLCAKICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGMoImRvY19pZCIsICJwYXJhZ3JhcGhfaWQiLCAic2VudGVuY2VfaWQiKSkKCiAgd29yZG5ldHdvcmsgPC0gaGVhZChjb29jLCA2MCkKICB3b3JkbmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUod29yZG5ldHdvcmspCiAgCiAgZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gInBpbmsiKSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgY29sID0gImRhcmtncmVlbiIsIHNpemUgPSA0KSArCiAgICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEJFRk9SRSIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIikKICAKfQoKQ09fT0Nfbm91bl9hZGpfc2FtZV9zZW50LmFmdGVyIDwtIGZ1bmN0aW9uKGRmMil7CiAgCiAgbGlicmFyeShpZ3JhcGgpCiAgbGlicmFyeShnZ3JhcGgpCiAgbGlicmFyeShnZ3Bsb3QyKQogIAogIGNvb2MgPC0gY29vY2N1cnJlbmNlKHggPSBzdWJzZXQoZGYyLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSksIAogICAgICAgICAgICAgICAgICAgICAgIHRlcm0gPSAibGVtbWEiLCAKICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGMoImRvY19pZCIsICJwYXJhZ3JhcGhfaWQiLCAic2VudGVuY2VfaWQiKSkKCiAgd29yZG5ldHdvcmsgPC0gaGVhZChjb29jLCA2MCkKICB3b3JkbmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUod29yZG5ldHdvcmspCiAgCiAgZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gImxpZ2h0Z3JlZW4iKSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgY29sID0gImRhcmtibHVlIiwgc2l6ZSA9IDQpICsKICAgIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicyh0aXRsZSA9ICJDb29jY3VycmVuY2VzIHdpdGhpbiBzZW50ZW5jZTogQUZURVIiLCBzdWJ0aXRsZSA9ICJOb3VucyAmIEFkamVjdGl2ZSIpCiAgCn0KCgpDT19PQ19ub3VuX2Fkal9zYW1lX3NlbnQuYmVmb3JlKHhfb2RkLmJlZm9yZSkKQ09fT0Nfbm91bl9hZGpfc2FtZV9zZW50LmFmdGVyKHhfZXZlbi5hZnRlcikKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCkNPX09DX25vdW5fYWRqX2ZvbGxvd2luZy5iZWZvcmUgPC0gZnVuY3Rpb24oZGYpewogIGNvb2MgPC0gY29vY2N1cnJlbmNlKGRmJGxlbW1hLCByZWxldmFudCA9IGRmJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpLCBza2lwZ3JhbSA9IDEpCiAgaGVhZChjb29jKQogIAogIHdvcmRuZXR3b3JrIDwtIGhlYWQoY29vYywgNjApCiAgd29yZG5ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKHdvcmRuZXR3b3JrKQogIGdncmFwaCh3b3JkbmV0d29yaywgbGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJsaWdodGdyZWVuIikgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrZ3JlZW4iLCBzaXplID0gNCkgKwogICAgdGhlbWVfZ3JhcGgoYmFzZV9mYW1pbHkgPSAiQXJpYWwgTmFycm93IikgKwogICAgbGFicyh0aXRsZSA9ICJXb3JkcyBmb2xsb3dpbmcgb25lIGFub3RoZXI6IEJFRk9SRSIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIikKfQoKQ09fT0Nfbm91bl9hZGpfZm9sbG93aW5nLmFmdGVyIDwtIGZ1bmN0aW9uKGRmKXsKICBjb29jIDwtIGNvb2NjdXJyZW5jZShkZiRsZW1tYSwgcmVsZXZhbnQgPSBkZiR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSwgc2tpcGdyYW0gPSAxKQogIGhlYWQoY29vYykKICAKICB3b3JkbmV0d29yayA8LSBoZWFkKGNvb2MsIDYwKQogIHdvcmRuZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSh3b3JkbmV0d29yaykKICBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAic2t5Ymx1ZSIpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2JsdWUiLCBzaXplID0gNCkgKwogICAgdGhlbWVfZ3JhcGgoYmFzZV9mYW1pbHkgPSAiQXJpYWwgTmFycm93IikgKwogICAgbGFicyh0aXRsZSA9ICJXb3JkcyBmb2xsb3dpbmcgb25lIGFub3RoZXI6IEFGVEVSIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUiKQp9CgoKQ09fT0Nfbm91bl9hZGpfZm9sbG93aW5nLmJlZm9yZSh4X29kZC5iZWZvcmUpCkNPX09DX25vdW5fYWRqX2ZvbGxvd2luZy5hZnRlcih4X2V2ZW4uYWZ0ZXIpCgpgYGAKCgoKIyMgQ29vY2N1cmVuY2VzIChwYXJ0IDIpCgpgYGB7ciwgZWNobz1GQUxTRX0KCkNvcnJzIDwtIGZ1bmN0aW9uKGRmKXsKICBkZiRpZCA8LSB1bmlxdWVfaWRlbnRpZmllcihkZiwgZmllbGRzID0gYygic2VudGVuY2VfaWQiLCAiZG9jX2lkIikpCiAgZHRtIDwtIHN1YnNldChkZiwgdXBvcyAlaW4lIGMoIk5PVU4iLCAiQURKIikpCiAgZHRtIDwtIGRvY3VtZW50X3Rlcm1fZnJlcXVlbmNpZXMoZHRtLCBkb2N1bWVudCA9ICJpZCIsIHRlcm0gPSAibGVtbWEiKQogIGR0bSA8LSBkb2N1bWVudF90ZXJtX21hdHJpeChkdG0pCiAgZHRtIDwtIGR0bV9yZW1vdmVfbG93ZnJlcShkdG0sIG1pbmZyZXEgPSA1KQogIHRlcm1jb3JyZWxhdGlvbnMgPC0gZHRtX2NvcihkdG0pCiAgeSA8LSBhc19jb29jY3VycmVuY2UodGVybWNvcnJlbGF0aW9ucykKICB5IDwtIHN1YnNldCh5LCB0ZXJtMSA8IHRlcm0yICYgYWJzKGNvb2MpID4gMC4yKQogIHkgPC0geVtvcmRlcihhYnMoeSRjb29jKSwgZGVjcmVhc2luZyA9IFRSVUUpLCBdCiAgeVsxOjI1LF0KfQoKYGBgCgpgYGB7cn0KCkNvcnJzKHhfb2RkLmJlZm9yZSkKQ29ycnMoeF9ldmVuLmFmdGVyKQoKYGBgCgoKIyBFeHRyZW0oaXN0KSBGaWdodGluJyBXb3JkcyBPdmVyIFRpbWUKCgoKCgoKCgoKYGBge3IgZmluYWwsIGVjaG89RkFMU0V9CgpybShsaXN0PWxzKCkpCgpgYGAKCgoKCgoKCgpbaG9tZV0oaHR0cHM6Ly9icmVncmVlbi5naXRodWIuaW8vKQo=